"""
配置管理模块
处理配置的读写，支持从Redis加载配置到内存缓存，并提供动态获取配置的接口
["zh_female_vv_jupiter_bigtts", "zh_female_xiaohe_jupiter_bigtts", "zh_male_yunzhou_jupiter_bigtts",
              "zh_male_xiaotian_jupiter_bigtts"]
"""
import json
import copy
import threading
import redis
from typing import Dict, Any, Optional
from settings import REDIS_HOST, REDIS_PORT, REDIS_DB, REDIS_PASSWORD, REDIS_CONFIG_KEY

# 默认配置
DEFAULT_CONFIG = {
    "asr": {
        "extra": {
            "end_smooth_window_ms": 1500,
        },
    },
    "kcb": "喂{greeting}",
    "sms_content":"这是一条短信。",
    "model_speaker": {
        "boys": ["云舟","小天"],
        "girls": ["薇薇", "小荷"]
    },
    "tts": {
        "speaker": "zh_male_yunzhou_jupiter_bigtts",
        "audio_config": {
            "channel": 1,
            "format": "pcm",
            "sample_rate": 24000
        },
    },
    "dialog": {
        "bot_name": "钱牛牛",
        "system_role": """
        一、人设与沟通基调
            身份定位：你是一名助贷公司业务部经理，从事金融助贷行业8年，5年银行信贷部工作经验，是一名资深金融产品专家，
                    专业度拉满且自带风趣，在沟通问题时说话语气坚定不容置疑！可掌控客户情绪和谈话节奏引导客户聊天和动作。
            公司地址：瑶海区大东门新交通大厦3207室
        二、关键原则（时刻牢记）
            "保持简单直接高效的沟通" "不闲聊"
            目标优先：所有沟通均以询问句结尾，最终目标筛选意向客户通过短信链接添加微信了解详情！！
        """,
        "speaking_style": "你的说话风格自信大方简洁明了语气坚定不容置疑，任何下场景都不要用沮丧语气，全程保持白话自然的沟通，不闲聊，语速适中稍快，语调自然有起伏。",
        "location": {
            "city": "合肥",
        },
        "extra": {
            "strict_audit": False,
            "audit_response": "",
            "recv_timeout": 10,
            "input_mod": "audio"
        }
    },
}


class ConfigManager:
    """配置管理器，负责从Redis加载配置并提供内存缓存"""
    
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls):
        """单例模式"""
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super(ConfigManager, cls).__new__(cls)
                    cls._instance._initialized = False
        return cls._instance
    
    def __init__(self):
        """初始化配置管理器"""
        if self._initialized:
            return
        
        self._initialized = True
        self._redis_client = None
        self._config_cache = None  # 内存缓存
        self._init_redis()
        self._load_config_from_redis()
    
    def _init_redis(self):
        """初始化Redis连接"""
        try:
            self._redis_client = redis.Redis(
                host=REDIS_HOST,
                port=REDIS_PORT,
                db=REDIS_DB,
                password=REDIS_PASSWORD,
                decode_responses=True,
                socket_timeout=2,
            )
            # 测试连接
            self._redis_client.ping()
        except Exception as e:
            print(f"Redis 初始化失败: {e}")
            self._redis_client = None
    
    def _load_config_from_redis(self):
        """从Redis加载配置到内存缓存"""
        if self._redis_client is None:
            print("Redis未连接，使用默认配置")
            self._config_cache = copy.deepcopy(DEFAULT_CONFIG)
            return
        
        try:
            config_str = self._redis_client.get(REDIS_CONFIG_KEY)
            if config_str:
                self._config_cache = json.loads(config_str)
                print("已从Redis加载配置")
            else:
                # Redis中没有配置，使用默认配置并保存到Redis
                self._config_cache = copy.deepcopy(DEFAULT_CONFIG)
                self._save_config_to_redis()
                print("Redis中没有配置，使用默认配置并保存到Redis")
        except json.JSONDecodeError as e:
            print(f"解析Redis配置JSON失败: {e}，使用默认配置")
            self._config_cache = copy.deepcopy(DEFAULT_CONFIG)
        except Exception as e:
            print(f"从Redis加载配置失败: {e}，使用默认配置")
            self._config_cache = copy.deepcopy(DEFAULT_CONFIG)
    
    def _save_config_to_redis(self):
        """保存配置到Redis"""
        if self._redis_client is None:
            print("Redis未连接，无法保存配置")
            return False
        
        try:
            config_str = json.dumps(self._config_cache, ensure_ascii=False)
            self._redis_client.set(REDIS_CONFIG_KEY, config_str)
            print("配置已保存到Redis")
            return True
        except Exception as e:
            print(f"保存配置到Redis失败: {e}")
            return False
    
    def get_config(self) -> Dict[str, Any]:
        """获取配置（优先从内存缓存读取）
        
        Returns:
            dict: 配置字典的深拷贝
        """
        if self._config_cache is None:
            self._load_config_from_redis()
        return copy.deepcopy(self._config_cache)
    
    def update_config(self, config: Dict[str, Any]) -> bool:
        """更新配置（同时更新内存缓存和Redis）
        
        Args:
            config: 新的配置字典
            
        Returns:
            bool: 是否更新成功
        """
        try:
            # 验证配置结构
            self._validate_config(config)
            # 更新内存缓存
            self._config_cache = copy.deepcopy(config)
            # 保存到Redis
            return self._save_config_to_redis()
        except Exception as e:
            print(f"更新配置失败: {e}")
            return False
    
    def _validate_config(self, config: Dict[str, Any]):
        """验证配置结构
        
        Args:
            config: 配置字典
            
        Raises:
            ValueError: 如果配置结构不正确
        """
        required_keys = ["asr", "tts", "dialog"]
        for key in required_keys:
            if key not in config:
                raise ValueError(f"配置缺少必需的键: {key}")
        
        # 验证dialog.extra
        if "extra" not in config.get("dialog", {}):
            raise ValueError("配置缺少 dialog.extra")
    
    def get_config_value(self, key_path: str, default: Any = None) -> Any:
        """通过路径获取配置值（如 "dialog.bot_name"）
        
        Args:
            key_path: 配置路径，使用点号分隔，如 "dialog.bot_name"
            default: 默认值
            
        Returns:
            配置值或默认值
        """
        if self._config_cache is None:
            self._load_config_from_redis()
        
        keys = key_path.split(".")
        value = self._config_cache
        try:
            for key in keys:
                value = value[key]
            return value
        except (KeyError, TypeError):
            return default
    
    def update_config_value(self, key_path: str, value: Any) -> bool:
        """通过路径更新配置值（如 "dialog.bot_name"）
        
        Args:
            key_path: 配置路径，使用点号分隔，如 "dialog.bot_name"
            value: 新值
            
        Returns:
            bool: 是否更新成功
        """
        if self._config_cache is None:
            self._load_config_from_redis()
        
        keys = key_path.split(".")
        config = self._config_cache
        
        try:
            # 导航到父节点
            for key in keys[:-1]:
                if key not in config:
                    config[key] = {}
                config = config[key]
            
            # 设置值
            config[keys[-1]] = value
            # 保存到Redis
            return self._save_config_to_redis()
        except Exception as e:
            print(f"更新配置值失败: {e}")
            return False
    
    def reload_config(self):
        """重新从Redis加载配置"""
        self._load_config_from_redis()


# 全局单例实例
_config_manager = None

def get_config_manager() -> ConfigManager:
    """获取配置管理器单例实例"""
    global _config_manager
    if _config_manager is None:
        _config_manager = ConfigManager()
    return _config_manager

